package com.authine.cloudpivot.ext.applicationservice.authority;

import com.alibaba.cola.dto.MultiResponse;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.BizException;
import com.alibaba.cola.exception.Exceptions;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.common.organization.feign.LabelFeignServiceI;
import com.authine.cloudpivot.common.organization.model.Label;
import com.authine.cloudpivot.common.organization.model.LabelUser;
import com.authine.cloudpivot.common.organization.model.LabelUserScope;
import com.authine.cloudpivot.common.organization.model.ValidableList;
import com.authine.cloudpivot.common.organization.model.enums.LabelType;
import com.authine.cloudpivot.common.organization.model.enums.ShareType;
import com.authine.cloudpivot.common.organization.model.enums.UnitType;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.dto.system.TagScopeDto;
import com.authine.cloudpivot.ext.utils.BoServiceUtils;
import com.authine.cloudpivot.ext.utils.system.BeanUtils;
import com.authine.common.util.ObjectMapperUtils;
import com.authine.hermes.app.launcher.org.v2.OrganizationV2;
import com.authine.hermes.app.launcher.service.ApplicationService;
import com.authine.mvp.app.launcher.domain.SelectorFormat;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.authine.mvp.app.launcher.dto.bo.response.BO;
import com.authine.mvp.app.launcher.dto.bo.response.BOList;
import com.authine.mvp.app.launcher.dto.errorcode.ErrorCodeEnum;
import com.google.common.collect.Maps;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.authine.hermes.app.launcher.service.ApplicationServiceFoundation.CUSTOM_SERVICE;

/**
 * @ClassName TagScopeService
 * @Description: 管理范围服务
 * @Author fj
 * @Date 2021/10/16
 * @Version V1.0
 **/
@Path("TagScopeService")
@Slf4j
public class TagScopeService extends ApplicationService {
    //    private static final RoleFeignServiceI roleFeignServiceI = ApplicationContextUtils.getBean(RoleFeignServiceI.class);
    private static final LabelFeignServiceI labelFeignServiceI = ApplicationContextUtils.getBean(LabelFeignServiceI.class);
    /**
     * 新增标签管理范围
     *
     * @param tagScopeDto 请求参数
     * @return 树形列表
     */
    @Path("addTagScope")
    @POST
    @Operation(summary = "新增标签管理范围", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> addTagScope(@Parameter TagScopeDto tagScopeDto) {
        Assert.notEmpty(tagScopeDto.getOrganization_id(), "标签归属组织不能为空！");
        Assert.notNull(tagScopeDto.getGroup_name(), "标签组名称不能为空！");
        Assert.notNull(tagScopeDto.getTag_name(), "标签名称不能为空！");
        Assert.notNull(tagScopeDto.getScope_type(), "标签管理范围类型不能为空！");

        createGroup(tagScopeDto);

        createRole(tagScopeDto);

        // fixme 2021.10.21。新增标签的时候，不选择人员范围。当用户选择的角色是按标签授权时，新增标签人员，避免导致角色、标签、用户互相引用，影响用户操作。
        //createRoleUser(tagScopeDto);

        Map<String, Object> tagScopeMap = BeanUtils.bean2Map(tagScopeDto);

        // 新增标签管理范围
        SingleResponse<BO> createBO = BoServiceUtils.createBo(ModelConst.T_TAG_SCOPE, Collections.singletonList(tagScopeMap));
        log.info("------------------------新增标签管理范围成功：{}------------------------", JSONObject.toJSONString(createBO));
        return createBO;
    }

    /**
     * 修改标签管理范围
     *
     * @param tagScopeDto 请求参数
     * @return 树形列表
     */
    @Path("updateTagScope")
    @POST
    @Operation(summary = "修改标签管理范围", tags = CUSTOM_SERVICE)
    public SingleResponse<BO> updateTagScope(@Parameter TagScopeDto tagScopeDto) {
        Assert.notEmpty(tagScopeDto.getOrganization_id(), "标签归属组织不能为空！");
        Assert.notNull(tagScopeDto.getGroup_name(), "标签组名称不能为空！");
        Assert.notNull(tagScopeDto.getTag_name(), "标签名称不能为空！");
        Assert.notNull(tagScopeDto.getScope_type(), "标签管理范围类型不能为空！");

        updateGroup(tagScopeDto);

        updateRole(tagScopeDto);

        // 修改标签角色时会修改用户信息，故将请求参数做一次深拷贝
        TagScopeDto target = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(tagScopeDto), TagScopeDto.class);

        if (!CollectionUtils.isEmpty(tagScopeDto.getUser_ids())) {
            updateRoleUser(target);
        }

        Map<String, Object> tagScopeMap = BeanUtils.bean2Map(tagScopeDto);

        // 修改标签管理范围
        SingleResponse<BO> updateBO = BoServiceUtils.updateMainBo(ModelConst.T_TAG_SCOPE, tagScopeMap);
        log.info("------------------------修改标签管理范围成功：{}------------------------", JSONObject.toJSONString(updateBO));
        return updateBO;
    }

    /**
     * 新增标签组
     *
     * @param tagScopeDto 标签管理范围
     */
    private void createGroup(TagScopeDto tagScopeDto) {
        Label group = new Label();
        group.setName(tagScopeDto.getGroup_name());
        group.setLabelType(LabelType.GROUP);
        group.setShareType(ShareType.ORG);
        // 通过组织对应的部门id获取组织信息
        MultiResponse<OrganizationV2> organizationV2MultiResponse = this.orgServiceV2.listOrganization();
        if (!organizationV2MultiResponse.isSuccess()) {
            throw new BizException(organizationV2MultiResponse.getErrMessage());
        }
        log.info("------------------------获取所有组织信息：{}------------------------", JSONObject.toJSONString(organizationV2MultiResponse));
        OrganizationV2 organizationV2 = organizationV2MultiResponse.getData().stream().filter(org -> tagScopeDto.getOrganization_id().get(0).getId().equals(org.getDepartmentId()))
                .findFirst().orElseThrow(() -> new BizException("组织不存在，请初始化数据"));
        group.setOrgId(organizationV2.getId());
        log.info("------------------------新增标签组请求参数：{}------------------------", JSONObject.toJSONString(group));
        SingleResponse<Label> createGroupResponse = labelFeignServiceI.createLabel(group);
        log.info("------------------------新增标签组返回结果：{}------------------------", JSONObject.toJSONString(createGroupResponse));
        if (!createGroupResponse.isSuccess()) {
            throw new BizException(createGroupResponse.getErrMessage());
        }
        tagScopeDto.setGroup_id(createGroupResponse.getData().getId());
    }

    /**
     * 修改标签组
     *
     * @param tagScopeDto 标签管理范围
     */
    private void updateGroup(TagScopeDto tagScopeDto) {
        Label group = new Label();
        group.setName(tagScopeDto.getGroup_name());
        group.setLabelType(LabelType.GROUP);
        group.setId(tagScopeDto.getGroup_id());
        log.info("------------------------修改标签组请求参数：{}------------------------", JSONObject.toJSONString(group));
        SingleResponse<Label> updateGroupResponse = labelFeignServiceI.updateLabel(group);
        log.info("------------------------修改标签组返回结果：{}------------------------", JSONObject.toJSONString(updateGroupResponse));
        if (!updateGroupResponse.isSuccess()) {
            throw new BizException(updateGroupResponse.getErrMessage());
        }
    }

    /**
     * 新增标签
     *
     * @param tagScopeDto 标签管理范围
     */
    private void createRole(TagScopeDto tagScopeDto) {
        Label role = new Label();
        role.setName(tagScopeDto.getTag_name());
        role.setLabelType(LabelType.LABEL);
        role.setShareType(ShareType.ORG);
        MultiResponse<OrganizationV2> organizationV2MultiResponse = this.orgServiceV2.listOrganization();
        if (!organizationV2MultiResponse.isSuccess()) {
            throw new BizException(organizationV2MultiResponse.getErrMessage());
        }
        log.info("------------------------获取所有组织信息：{}------------------------", JSONObject.toJSONString(organizationV2MultiResponse));
        OrganizationV2 organizationV2 = organizationV2MultiResponse.getData().stream()
                .filter(org -> tagScopeDto.getOrganization_id().get(0).getId().equals(org.getDepartmentId()))
                .findFirst().orElseThrow(() -> new BizException("组织不存在，请初始化数据"));
        role.setOrgId(organizationV2.getId());
        role.setParentId(tagScopeDto.getGroup_id());
        log.info("------------------------新增标签请求参数：{}------------------------", JSONObject.toJSONString(role));
        SingleResponse<Label> createRoleResponse = labelFeignServiceI.createLabel(role);
        log.info("------------------------新增标签返回结果：{}------------------------", JSONObject.toJSONString(createRoleResponse));

        if (!createRoleResponse.isSuccess()) {
            throw new BizException(createRoleResponse.getErrMessage());
        }
        tagScopeDto.setTag_id(createRoleResponse.getData().getId());
    }

    /**
     * 修改标签
     *
     * @param tagScopeDto 标签管理范围
     */
    private void updateRole(TagScopeDto tagScopeDto) {
        Label role = new Label();
        role.setName(tagScopeDto.getTag_name());
        role.setLabelType(LabelType.LABEL);
        role.setId(tagScopeDto.getTag_id());
        log.info("------------------------修改标签请求参数：{}------------------------", JSONObject.toJSONString(role));
        SingleResponse<Label> updateRoleResponse = labelFeignServiceI.updateLabel(role);
        log.info("------------------------修改标签返回结果：{}------------------------", JSONObject.toJSONString(updateRoleResponse));
        if (!updateRoleResponse.isSuccess()) {
            throw new BizException(updateRoleResponse.getErrMessage());
        }
    }

    /**
     * 新增标签用户
     *
     * @param tagScopeDto 标签管理范围
     */
    public void createRoleUser(TagScopeDto tagScopeDto) {
        // 添加标签用户
        ValidableList<LabelUser> labelUserList = new ValidableList<>();
        tagScopeDto.getUser_ids().forEach(userId -> {
            LabelUser labelUser = new LabelUser();
            // 标签管理范围(人员)
            labelUser.setType(UnitType.USER);
            labelUser.setUnitId(userId.getId());
            labelUserList.add(labelUser);
        });
        log.info("------------------------新增标签用户请求参数：{},labelId：{}------------------------", JSONObject.toJSONString(labelUserList), tagScopeDto.getTag_id());
        MultiResponse<LabelUser> createRoleUserResponse = labelFeignServiceI.createLabelUnit(tagScopeDto.getTag_id(), labelUserList);
        log.info("------------------------新增标签用户返回结果：{}------------------------", JSONObject.toJSONString(createRoleUserResponse));
        if (!createRoleUserResponse.isSuccess()) {
            throw new BizException(createRoleUserResponse.getErrMessage());
        }

        // 向标签用户中间表插入数据
        List<Map<String, Object>> labelUserDataList = Lists.newArrayList();
        Map<String, Object> labelUserDataMap;
        for (LabelUser labelUser: createRoleUserResponse.getData()) {
            labelUserDataMap = Maps.newHashMap();
            labelUserDataMap.put("id", labelUser.getId());
            labelUserDataMap.put("label_id", labelUser.getLabelId());
            labelUserDataMap.put("unit_id", labelUser.getUnitId());
            labelUserDataMap.put("type", labelUser.getType().getIndex());
            labelUserDataList.add(labelUserDataMap);
        }
        SingleResponse<BO> createLabelUserBO = BoServiceUtils.createBo(ModelConst.T_LABEL_USER, labelUserDataList);
        if (!createLabelUserBO.isSuccess()) {
            Exceptions.throwBizException(ErrorCodeEnum.BO_SAVE_ERROR);
        }

        // 设置标签用户管理范围
        ValidableList<LabelUserScope> labelUserScopeList = new ValidableList<>();
        if ("0".equals(tagScopeDto.getScope_type())) {
            tagScopeDto.getUs_scopes().forEach(usScope -> {
                LabelUserScope labelUserScope = new LabelUserScope();
                labelUserScope.setUnitId(usScope.getId());
                labelUserScope.setType(UnitType.USER);
                labelUserScopeList.add(labelUserScope);
            });
        } else {
            tagScopeDto.getOu_scopes().forEach(ouScope -> {
                LabelUserScope labelUserScope = new LabelUserScope();
                labelUserScope.setUnitId(ouScope.getId());
                labelUserScope.setType(UnitType.DEPARTMENT);
                labelUserScopeList.add(labelUserScope);
            });
        }
        createRoleUserResponse.getData().forEach(roleUser -> {
            log.info("------------------------设置用户管理范围请求参数：{},labelId：{}------------------------", JSONObject.toJSONString(labelUserScopeList), roleUser.getId());
            MultiResponse<LabelUserScope> labelUserScopeResponse = labelFeignServiceI.updateLabelUnitScope(roleUser.getId(), labelUserScopeList);
            log.info("------------------------设置用户管理范围返回结果：{}------------------------", JSONObject.toJSONString(labelUserScopeResponse));
            if (labelUserScopeResponse.isSuccess()) {
                throw new BizException(labelUserScopeResponse.getErrMessage());
            }
        });
    }

    /**
     * 修改标签用户
     *
     * @param tagScopeDto 标签管理范围
     */
    public void updateRoleUser(TagScopeDto tagScopeDto) {
        SingleResponse<BOList> tagScopeByTagId = BoServiceUtils.findListBySimple(ModelConst.T_TAG_SCOPE, "tag_id", tagScopeDto.getTag_id());
        log.info("------------------------根据标签id查询标签管理范围：{}------------------------", JSONObject.toJSONString(tagScopeByTagId));
        TagScopeDto oldTagScope = ObjectMapperUtils.fromJSON(ObjectMapperUtils.toJSONString(tagScopeByTagId.getData().getData().get(0)), TagScopeDto.class);

        // 通过标签id获取修改之前的人员范围id
        List<String> oldUserIdList = oldTagScope.getUser_ids().stream().map(SelectorFormat::getId).collect(Collectors.toList());

        // 获取修改之后的人员范围id
        List<String> newUserIdList = tagScopeDto.getUser_ids().stream().map(SelectorFormat::getId).collect(Collectors.toList());

        // 需要删除的用户id
        List<String> removeUserIdList = getRemoveUserIdList(oldUserIdList, newUserIdList);

        // 根据标签id查询所有标签用户信息
        SingleResponse<BOList> labelUserBOList = BoServiceUtils.findListBySimple(ModelConst.T_LABEL_USER, "label_id", tagScopeDto.getTag_id());
        log.info("------------------------根据标签id查询所有标签用户信息：{}------------------------", JSONObject.toJSONString(labelUserBOList));

        // 需要删除的标签用户信息
        List<Map<String, Object>> filterLabelUserVOList = labelUserBOList.getData().getData().stream().filter(labelUser -> removeUserIdList.contains(String.valueOf(labelUser.get("unit_id")))).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(filterLabelUserVOList)) {
            List<String> labelUserId = filterLabelUserVOList.stream().map(labelUser -> String.valueOf(labelUser.get("id"))).collect(Collectors.toList());
            SingleResponse<?> removeRoleUserResponse = labelFeignServiceI.deleteLabelUnit(labelUserId);
            if (!removeRoleUserResponse.isSuccess()) {
                throw new BizException(removeRoleUserResponse.getErrMessage());
            }

            // 同步删除标签用户表
            BoServiceUtils.batchDeleteBO(ModelConst.T_LABEL_USER, labelUserId, true);
        }

        // 需要新增的标签用户
        List<SelectorFormat> createUserList = getCreateUserIdList(oldTagScope.getUser_ids(), tagScopeDto.getUser_ids());
        if (!CollectionUtils.isEmpty(createUserList)) {
            TagScopeDto target = new TagScopeDto();
            org.springframework.beans.BeanUtils.copyProperties(tagScopeDto, target);
            target.setUser_ids(createUserList);
            createRoleUser(target);
        }

        // 需要更新的标签用户
        tagScopeDto.getUser_ids().retainAll(oldTagScope.getUser_ids());
        if (!CollectionUtils.isEmpty(tagScopeDto.getUser_ids())) {
            // 设置标签用户管理范围
            ValidableList<LabelUserScope> labelUserScopeList = new ValidableList<>();
            if ("0".equals(tagScopeDto.getScope_type())) {
                tagScopeDto.getUs_scopes().forEach(usScope -> {
                    LabelUserScope labelUserScope = new LabelUserScope();
                    labelUserScope.setUnitId(usScope.getId());
                    labelUserScope.setType(UnitType.USER);
                });
            } else {
                tagScopeDto.getOu_scopes().forEach(ouScope -> {
                    LabelUserScope labelUserScope = new LabelUserScope();
                    labelUserScope.setUnitId(ouScope.getId());
                    labelUserScope.setType(UnitType.DEPARTMENT);
                });
            }
            tagScopeDto.getUser_ids().forEach(roleUser -> {
                MultiResponse<LabelUserScope> labelUserScopeResponse = labelFeignServiceI.updateLabelUnitScope(roleUser.getId(), labelUserScopeList);
                if (labelUserScopeResponse.isSuccess()) {
                    throw new BizException(labelUserScopeResponse.getErrMessage());
                }
            });
        }
    }

    /**
     * 获取需要删除的标签用户id
     *
     * @param oldUserIdList 更新之前的人员范围id
     * @param newUserIdList 更新之后的人员范围id
     */
    private List<String> getRemoveUserIdList(List<String> oldUserIdList, List<String> newUserIdList) {
        List<String> removeUserIdList = Lists.newArrayList();
        oldUserIdList.forEach(oldId -> {
            if (!newUserIdList.contains(oldId)) {
                removeUserIdList.add(oldId);
            }
        });
        return removeUserIdList;
    }

    /**
     * 获取需要添加的标签用户
     *
     * @param oldUserList 更新之前的人员范围
     * @param newUserList 更新之后的人员范围
     */
    private List<SelectorFormat> getCreateUserIdList(List<SelectorFormat> oldUserList, List<SelectorFormat> newUserList) {
        List<SelectorFormat> createUserList = Lists.newArrayList();
        newUserList.forEach(newUser -> {
            if (!oldUserList.contains(newUser)) {
                createUserList.add(newUser);
            }
        });
        return createUserList;
    }
}
